package nacos

import (
	"encoding/json"
	"github.com/nacos-group/nacos-sdk-go/clients"
	"github.com/nacos-group/nacos-sdk-go/common/constant"
	"github.com/nacos-group/nacos-sdk-go/vo"
	"log/lg"
	"sync"
)

// Conf 初始化配置json
type Conf struct {
	Path  string `json:"path"`  //采集日志路径
	Topic string `json:"topic"` //跟路径对应的 消息队列主题
}

// NaCos 初始化对象
type NaCos struct {
	clientConfig  *constant.ClientConfig  //NaCos-server的配置
	serverConfigs []constant.ServerConfig //初始化连接NaCos配置,可以设置多少个NaCos服务
}

// NewObj 构造结构体,初始化相关参数
func NewObj(addr string) (NaCosObj *NaCos) {
	NaCosObj = &NaCos{
		//初始化NaCos的相关参数配置
		clientConfig: &constant.ClientConfig{
			NamespaceId:         "", // 如果需要支持多namespace，我们可以场景多个client,它们有不同的NamespaceId。当namespace是public时，此处填空字符串。
			TimeoutMs:           5000,
			NotLoadCacheAtStart: true,
			LogDir:              "nacos/log",
			CacheDir:            "nacos/cache",
			RotateTime:          "1h",
			MaxAge:              3,
			LogLevel:            "info",
		},
		//初始化NaCos集群连接,可以配置多个
		serverConfigs: []constant.ServerConfig{
			{
				IpAddr:      addr,
				ContextPath: "/nacos",
				Port:        8848,
				Scheme:      "http",
			},
		},
	}
	return
}

// Client 服务注册方法
func (n *NaCos) Client(ServiceName string) {
	// 创建服务发现客户端的另一种方式 (推荐)
	namingClient, err := clients.NewNamingClient(
		vo.NacosClientParam{
			ClientConfig:  n.clientConfig,
			ServerConfigs: n.serverConfigs,
		},
	)
	if err != nil {
		lg.Log.Error("初始化服务注册客户端失败:", err)
		return
	}
	//向NaCos开始注册
	success, err := namingClient.RegisterInstance(vo.RegisterInstanceParam{
		Ip:          "192.168.3.135", //需要填写本地ip地址
		Port:        8080,
		ServiceName: ServiceName,
		Weight:      10,
		Enable:      true,
		Healthy:     true,
		Ephemeral:   true,
		Metadata:    map[string]string{"idc": "shanghai"}, //注册的机房地址
		ClusterName: "cluster-a",                          //注册的集群
		GroupName:   "group-a",                            // 注册的分组
	})
	if err != nil {
		lg.Log.Error("初始化服务注册客户端失败:", err)
		return
	}
	if success {
		lg.Log.Info("注册成功")
	}

	return
}

// GetConfig 获取配置1次,	返回一个初始化切片结构体,可以放置多个配置
func (n *NaCos) GetConfig(dataId, group string) (conf []*Conf) {
	// 创建动态配置客户端的另一种方式 (推荐)
	configClient, _ := clients.NewConfigClient(
		vo.NacosClientParam{
			ClientConfig:  n.clientConfig,
			ServerConfigs: n.serverConfigs,
		},
	)

	//获取配置：GetConfig对象
	content, err := configClient.GetConfig(vo.ConfigParam{
		DataId: dataId,
		Group:  group})
	if err != nil {
		lg.Log.Error("获取配置错误:", err)
		return
	}

	//解析获取的配置,转成json格式
	err = json.Unmarshal([]byte(content), &conf)
	if err != nil {
		lg.Log.Error("配置解析json出错:", err)
		return
	}

	return
}

// ListenConf 监听配置变化
func (n *NaCos) ListenConf(dataId, group string, newConfChan chan<- []*Conf) {
	// 创建动态配置客户端的另一种方式 (推荐)
	configClient, _ := clients.NewConfigClient(
		vo.NacosClientParam{
			ClientConfig:  n.clientConfig,
			ServerConfigs: n.serverConfigs,
		},
	)

	var wg sync.WaitGroup
	wg.Add(1)
	//排出去一个哨兵进行监听
	err := configClient.ListenConfig(vo.ConfigParam{
		DataId: dataId, //监听的id
		Group:  group,  //监听的组
		OnChange: func(namespace, group, dataId, data string) {
			//获取到配置后,通知到相关实例调用
			var newConf []*Conf
			err := json.Unmarshal([]byte(data), &newConf)
			if err != nil {
				lg.Log.Error("nacos哨兵解析配置出错")
				panic(err)
			}
			lg.Log.Info("nacos哨兵获取配置成功")
			newConfChan <- newConf
			lg.Log.Info("group:" + group + ", dataId:" + dataId + ", data:" + data)

		},
	})
	if err != nil {
		lg.Log.Error(err)
	}
	defer wg.Done()
	lg.Log.Info("哨兵在正常监听配置中")
	wg.Wait()

	return

}
